package com.znf4.aop.log;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

/**
 * 系统日志切面类
 * 
 * @author agui
 *
 */
@Aspect
@Component
public class SysLogAspect {
	private static final Logger logger = LoggerFactory.getLogger(SysLogAspect.class);

	private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime");

	@Autowired(required = false)
	private HttpServletRequest request;

	private Map<String, Object> map;

	/**
	 * Controller层切点 注解拦截
	 */
	@Pointcut(value = "@annotation(com.znf4.aop.log.SysLog)")
	public void aspect() {
	}

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作的开始时间
	 * 
	 * @param joinPoint
	 *            切点
	 * @throws InterruptedException
	 */
	@Before("aspect()")
	public void doBefore(JoinPoint joinPoint) throws InterruptedException {

		getControllerMethod(joinPoint); // 初始化注解参数

		// 日志信息准备
		Date beginTime = new Date();
		beginTimeThreadLocal.set(beginTime);// 线程绑定变量（该数据只有当前请求的线程可见）
		if (logger.isDebugEnabled()) {// 这里日志级别为debug
			logger.debug("开始计时: {}  URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(beginTime),
					request.getRequestURI());
		}

	}

	/**
	 * 后置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 */
	@After("aspect()")
	public void doAfter(JoinPoint joinPoint) {

		System.out.println(" 后  ");

		String discription = (String) map.get("discription");
		// 打印JVM信息。
		long beginTime = beginTimeThreadLocal.get().getTime();// 得到线程绑定的局部变量（开始时间）
		long endTime = System.currentTimeMillis(); // 2、结束时间
		if (logger.isDebugEnabled()) {
			logger.debug("描述：{} ", discription);
			logger.debug("计时结束：{} ", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(endTime));
			logger.debug("URI: {} ", request.getRequestURI());
			logger.debug("耗时： {} ", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTime - beginTime));
			logger.debug("最大内存: {}m ", Runtime.getRuntime().maxMemory() / 1024 / 1024);
			logger.debug("已分配内存: {}m ", Runtime.getRuntime().totalMemory() / 1024 / 1024);
			logger.debug("已分配内存中的剩余空间: {}m ", Runtime.getRuntime().freeMemory() / 1024 / 1024);
			logger.debug("最大可用内存: {}m ", (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory()
					+ Runtime.getRuntime().freeMemory()) / 1024 / 1024);
		}

	}

	/**
	 * 异常通知 记录操作报错日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "aspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {

	}

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint
	 *            切点
	 * @return discription
	 */
	public void getControllerMethod(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		SysLog sysLog = method.getAnnotation(SysLog.class);
		String discription = sysLog.description(); // 日志描述信息
		map = new HashMap<String, Object>();
		map.put("discription", discription);
		System.out.println("获取到的注解信息 ：" + map);

	}

}
